﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;

namespace Afiniczny
{
    class Encrypter
    {
        private CipherAffineAlgorithm _cipherAffineAlgorithm;
        private int _a, _b;
        private int _blockSize;
        private int alphabetLenght;

        public Encrypter(CipherAffineAlgorithm cipherAffineAlgorithm)
        {
            _cipherAffineAlgorithm = cipherAffineAlgorithm;
            _a = _cipherAffineAlgorithm.GetKeyA();
            _b = _cipherAffineAlgorithm.GetKeyB();
            _blockSize = _cipherAffineAlgorithm.GetBlockSize();
            alphabetLenght = Alphabet.getAlphabetLenght();
        }

        public BigInteger CodeBlock(BigInteger a_blockValue)
        {
            return (_a * a_blockValue + _b) % BigInteger.Pow(Alphabet.getAlphabetLenght(), _blockSize);
        }

        public string[] SplitTextToBlocks(string a_text)
        {
            int rest = a_text.Length % _blockSize;
            int loopCount = a_text.Length / _blockSize;
            string[] textBlocks;

            if (rest > 0)
                textBlocks = new string[loopCount + 1];
            else
                textBlocks = new string[loopCount];

            for (int i = 0; i < loopCount; i++)
            {
                textBlocks[i] = a_text.Substring(i * _blockSize, _blockSize);
            }
            if (rest > 0)
                textBlocks[textBlocks.Length - 1] = a_text.Substring(a_text.Length - rest);

            return textBlocks;
        }

        public string GetEncryptedTextString(BigInteger[] encryptedTextDataTable)
        {
            string result = "";
            for (int i = 0; i < encryptedTextDataTable.Length; i++)
            {
                result += _cipherAffineAlgorithm.DecodeBlockToString(encryptedTextDataTable[i]);
                if (i != encryptedTextDataTable.Length - 1)
                    result += "|";
            }
            return result;
        }

        public string EncryptText(string text)
        {
            string[] textBlocks = SplitTextToBlocks(text);
            BigInteger[] result = new BigInteger[textBlocks.Length];

            for (int i = 0; i < textBlocks.Length; i++)
            {
                result[i] = CodeBlock(_cipherAffineAlgorithm.GetBlockFromText(textBlocks[i]));
            }

            return GetEncryptedTextString(result);
        }

    }
}
